/*
 *  Copyright 2007-2008 by Matthias Buch-Kromann <mbk.isv@cbs.dk>.
 *  *
 *  This file is part of the Open-source Dependency Toolkit (OSDT),
 *  see http://code.google.com/p/open-source-dependency-toolkit.
 *  
 *  The OSDT is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as 
 *  published by the Free Software Foundation, either version 3 of 
 *  the License, or (at your option) any later version.
 * 
 *  The OSDT is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 * 
 *  You should have received a copy of the GNU Lesser General Public 
 *  License along with the OSDT in the files COPYING and COPYING.LESSER.
 *  If not, see http://www.gnu.org/licenses.
 */

package org.osdtsystem.functions;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.osdtsystem.exceptions.FunctionRuntimeException;
import org.osdtsystem.graphs.GraphAccessor;

/**
 * An abstract function class containing methods shared by all functions. 
 * Every function that extends this abstract class should call the abstract
 * constructor, specifying the subexpressions that can be validly called
 * from the constructed function. Apart from the functions listed among the
 * subexpressions, the only functions that can be called are the named functions
 * returned by namedFunctions().
 * @param <V> the type of the values returned by the abstract function
 * @author Matthias Buch-Kromann <mbk.isv@cbs.dk>
 */
public abstract class AbstractSingletonFunction<V> extends AbstractFunction<V> 
        implements SingletonFunction<V> {
    
    AbstractSingletonFunction(Function<?>... subfunctions) {
        super(subfunctions);
    }
    
    @Override
    public final V singletonFunctionValue(LocalFunction<?, ?> caller, FunctionContext context, GraphAccessor accessor) {
        try {
            return _singletonFunctionValue(caller, context, accessor);
        } catch (FunctionRuntimeException e) {
            throw e;
        } catch (Exception e) {
            if (! callingToString) {
                throw new FunctionRuntimeException("Exception caught during function evaluation.\n" +
                    "function: " + this.toString("", "", caller, context, accessor) +
                    "context: " + context.toString() + "\n" +
                    "accessor: " + accessor.toString() + "\n" +
                    "caller: " + caller.toString() + "\n"
                    , e);
            } else {
                return null;
            }
        }
    }

    public abstract V _singletonFunctionValue(LocalFunction<?, ?> caller, FunctionContext context, GraphAccessor accessor);

    @Override
    public final List<V> _functionValue(LocalFunction<?, ?> caller, FunctionContext context,
            GraphAccessor accessor) {
        // Find singleton value
        V value = singletonFunctionValue(caller, context, accessor);
        
        // Return singleton value
        if (value != null) {
            Object[] raw = {value};
            return Arrays.asList((V[]) raw);
        } else {
            return Collections.emptyList();
        }
    }
}
